package com.heima.article.service.impl;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.service.HotArticleService;
import com.heima.common.contants.ArticleConstants;
import com.heima.common.contants.RedisConstants;
import com.heima.common.dtos.ResponseResult;
import com.heima.model.article.dtos.ArticleVisitStreamMsg;
import com.heima.model.article.dtos.HotArticleVo;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.utils.common.BeanHelper;
import com.heima.utils.common.JsonUtils;
import com.heima.wemedia.feign.WemediaFeign;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class HotArticleServiceImpl implements HotArticleService {
    @Autowired
    private ApArticleMapper apArticleMapper;
    @Autowired
    private WemediaFeign wemediaFeign;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Override
    public void computeHotArticle() {
        //查询最近5天文章
        //获取前第5的日期
        Date last5Day = DateTime.now().minusDays(5).toDate();
        List<ApArticle> articleList = apArticleMapper.findArticleListByLast5days(last5Day);

        //计算所有文章的分值
        List<HotArticleVo> hotArticleVoList = computeHotArticleScore(articleList);

        //查询所有频道列表
        ResponseResult<List<WmChannel>> responseResult = wemediaFeign.findList();

        if(responseResult.getCode().equals(200)){
            List<WmChannel> channelList = responseResult.getData();
            //缓存热点文章数据到Redis
            cacheHotArticles(hotArticleVoList,channelList);
        }
    }

    private void cacheHotArticles(List<HotArticleVo> hotArticleVos,List<WmChannel> channelList) {
        //按照频道分别缓存文章（截取分值较高的前30条）
        //遍历频道
        for(WmChannel channel:channelList){
            //过滤出属于当前频道的文章列表
            List<HotArticleVo> filterHotArticles = hotArticleVos.stream()
                    .filter(hotArticleVo -> hotArticleVo.getChannelId().equals(channel.getId()))
                    .collect(Collectors.toList());

            String key = RedisConstants.HOT_ARTICLE_FIRST_PAGE+channel.getId();
            //分值倒序，截取前30条，存入到Redis
            sortAndCacheHotArticles(key,filterHotArticles);
        }

        //缓存推荐频道的文章（截取分值较高的前30条）
        String key = RedisConstants.HOT_ARTICLE_FIRST_PAGE+RedisConstants.DEFAULT_TAG;
        sortAndCacheHotArticles(key,hotArticleVos);
    }

    /**
     * 分值倒序，截取前30条，存入到Redis
     * @param key
     * @param filterHotArticles
     */
    private void sortAndCacheHotArticles(String key, List<HotArticleVo> filterHotArticles) {
        //分值倒序
        /**
         * 升序，o1比较o2
         * 降序，o2比较o1
         */
        filterHotArticles.sort(new Comparator<HotArticleVo>() {
            @Override
            public int compare(HotArticleVo o1, HotArticleVo o2) {
                return o2.getScore().compareTo(o1.getScore());
            }
        });

        //如果数量超过30条,则截取前30条
        if(filterHotArticles.size()>30){
            filterHotArticles = filterHotArticles.subList(0,30);
        }

        redisTemplate.opsForValue().set(key, JsonUtils.toString(filterHotArticles));
    }

    /**
     * 计算所有文章的分值
     * @param articleList
     * @return
     */
    private List<HotArticleVo> computeHotArticleScore(List<ApArticle> articleList) {
        List<HotArticleVo> hotArticleVos = new ArrayList<>();
        if(CollectionUtils.isNotEmpty(articleList)){
            for(ApArticle apArticle:articleList){
                HotArticleVo hotArticleVo = BeanHelper.copyProperties(apArticle,HotArticleVo.class);
                //计算每篇文章的分值
                int score = computeScore(apArticle);
                hotArticleVo.setScore(score);
                hotArticleVos.add(hotArticleVo);
            }
        }
        return hotArticleVos;
    }

    /**
     * 计算一篇文章的分值
     * @param apArticle
     * @return
     */
    private int computeScore(ApArticle apArticle) {
        int score = 0;
        if(apArticle.getViews()!=null){
            score+=apArticle.getViews();
        }
        if(apArticle.getLikes()!=null){
            score+=apArticle.getLikes()* ArticleConstants.HOT_ARTICLE_LIKE_WEIGHT;
        }
        if(apArticle.getComment()!=null){
            score+=apArticle.getComment()*ArticleConstants.HOT_ARTICLE_COMMENT_WEIGHT;
        }
        if(apArticle.getCollection()!=null){
            score+=apArticle.getCollection()*ArticleConstants.HOT_ARTICLE_COLLECTION_WEIGHT;
        }
        return score;
    }


    @Override
    public void updateHotArticle(ArticleVisitStreamMsg streamMsg) {
        Long articleId = streamMsg.getArticleId();
        Long like = streamMsg.getLike();
        Long collect = streamMsg.getCollect();
        Long comment = streamMsg.getComment();
        Long view = streamMsg.getView();

        //查询文章是否存在
        ApArticle apArticle = apArticleMapper.selectById(articleId);
        if(apArticle==null){
            return;
        }

        //更新DB数据
        if(like!=null){
            apArticle.setLikes(apArticle.getLikes()+like.intValue());
        }
        if(collect!=null){
            apArticle.setCollection(apArticle.getCollection()+collect.intValue());
        }
        if(comment!=null){
            apArticle.setComment(apArticle.getComment()+comment.intValue());
        }
        if(view!=null){
            apArticle.setViews(apArticle.getViews()+view.intValue());
        }
        apArticleMapper.updateById(apArticle);

        //更新指定频道的缓存数据
        String key = RedisConstants.HOT_ARTICLE_FIRST_PAGE+apArticle.getChannelId();
        updateHotArticleCache(key,apArticle);

        //更新推荐频道的缓存数据
        key = RedisConstants.HOT_ARTICLE_FIRST_PAGE+RedisConstants.DEFAULT_TAG;
        updateHotArticleCache(key,apArticle);
    }

    /**
     * 更新缓存数据
     * @param apArticle
     */
    private void updateHotArticleCache(String key,ApArticle apArticle) {
        //取出当前缓存数据
        String redisData = redisTemplate.opsForValue().get(key);

        if(StringUtils.isNotEmpty(redisData)){
            //转换List集合
            List<HotArticleVo> hotArticleVoList = JsonUtils.toList(redisData, HotArticleVo.class);

            boolean flag = false;
            //计算文章新分值
            int score = computeScore(apArticle);
            //判断当前文章是否在缓存中
            for(HotArticleVo hotArticleVo:hotArticleVoList){
                if(hotArticleVo.getId().equals(apArticle.getId())){
                    //计算当前文章分值，更新其分值
                    hotArticleVo.setScore(score);
                    flag = true;
                }
            }

            //如果该文章不在缓存中
            if(!flag){
                 //把当前文章存入原来的缓存列表中
                HotArticleVo hotArticleVo = BeanHelper.copyProperties(apArticle, HotArticleVo.class);
                hotArticleVo.setScore(score);
                hotArticleVoList.add(hotArticleVo);
            }

            //再重新排序，存入缓存
            sortAndCacheHotArticles(key,hotArticleVoList);
        }
    }

}
